function [positions, time] = tracker(video_path, img_files, pos, target_sz, ...
	padding, kernel, lambda, output_sigma_factor, interp_factor, cell_size, ...
	features, show_visualization)
%其中频域的变量都以f结尾 
%TRACKER Kernelized/Dual Correlation Filter (KCF/DCF) tracking.
%   This function implements the pipeline for tracking with the KCF (by
%   choosing a non-linear kernel) and DCF (by choosing a linear kernel).
%
%   It is meant to be called by the interface function RUN_TRACKER, which
%   sets up the parameters and loads the video information.
%
%   Parameters:
%     VIDEO_PATH is the location of the image files (must end with a slash
%      '/' or '\').
%     IMG_FILES is a cell array of image file names.
%     POS and TARGET_SZ are the initial position and size of the target
%      (both in format [rows, columns]).
%     PADDING is the additional tracked region, for context, relative to 
%      the target size.
%     KERNEL is a struct describing the kernel. The field TYPE must be one
%      of 'gaussian', 'polynomial' or 'linear'. The optional fields SIGMA,
%      POLY_A and POLY_B are the parameters for the Gaussian and Polynomial
%      kernels.
%     OUTPUT_SIGMA_FACTOR is the spatial bandwidth of the regression
%      target, relative to the target size.
%     INTERP_FACTOR is the adaptation rate of the tracker.
%     CELL_SIZE is the number of pixels per cell (must be 1 if using raw
%      pixels).
%     FEATURES is a struct describing the used features (see GET_FEATURES).
%     SHOW_VISUALIZATION will show an interactive video if set to true.
%
%   Outputs:
%    POSITIONS is an Nx2 matrix of target positions over time (in the
%     format [rows, columns]).
%    TIME is the tracker execution time, without video loading/rendering.
%
%   Joao F. Henriques, 2014


	%if the target is large, lower the resolution, we don't need that much
	%detail
    %尺寸调整，如果目标尺寸过大就适当缩小
	resize_image = (sqrt(prod(target_sz)) >= 100);  %diagonal size >= threshold
	if resize_image,
		pos = floor(pos / 2);
		target_sz = floor(target_sz / 2);
	end


	%window size, taking padding into account
    %确定检测范围window_sz，作者将其设为跟踪框尺寸的1+padding倍
    %（如果有快速运动，目标在两帧间的移动超过了这个范围，会导致跟踪丢失？）
	window_sz = floor(target_sz * (1 + padding));
	
% 	%we could choose a size that is a power of two, for better FFT
% 	%performance. in practice it is slower, due to the larger window size.
% 	window_sz = 2 .^ nextpow2(window_sz);

	
	%create regression labels, gaussian shaped, with a bandwidth
	%proportional to target size
	output_sigma = sqrt(prod(target_sz)) * output_sigma_factor / cell_size; %用output_sigma_factor，cell_sz和跟踪框尺寸计算高斯标签的带宽output_sigma 
	yf = fft2(gaussian_shaped_labels(output_sigma, floor(window_sz / cell_size))); %先用gaussian_shaped_labels生成回归标签，然后进行傅里叶变换转换到频域上的yf

	%store pre-computed cosine window生成汉宁窗cos_window，尺寸与yf相同，
    %即floor(window_sz / cell_size)，检测范围window_sz中cell的个数。 
    %对信号进行傅里叶变换时，为了减少频谱泄漏，通常在采样后对信号加窗。
	cos_window = hann(size(yf,1)) * hann(size(yf,2))';	
	
	
	if show_visualization,  %create video interface  利用show_video将跟踪结果可视化 
		update_visualization = show_video(img_files, video_path, resize_image);
	end
	
	
	%note: variables ending with 'f' are in the Fourier domain.
    %position记录每帧目标中心位置，time记录用时，图片读取和显示的时间不计入
	time = 0;  %to calculate FPS
	positions = zeros(numel(img_files), 2);  %to calculate precision
    
    %开始逐帧进行跟踪
	for frame = 1:numel(img_files),
		%load image 图像预处理，图片读取为im，转为灰度图，图片读取的时间不计入总时间
		im = imread([video_path img_files{frame}]);
		if size(im,3) > 1,
			im = rgb2gray(im);
		end
		if resize_image,
			im = imresize(im, 0.5);
		end

		tic()

		if frame > 1,
            %为第一帧后的跟踪过程，跳过来到129行，利用第一帧图像进行初始化 
			%obtain a subwindow for detection at the position from last
			%frame, and convert to Fourier domain (its size is unchanged)
			patch = get_subwindow(im, pos, window_sz);%在上一帧的跟踪结果pos的基础上，根据window_sz在这一帧图像上提取检测区域patch 
%这一帧的训练，与下一帧的检测，使用的是同一块patch 
			zf = fft2(get_features(patch, features, cell_size, cos_window));%利用get_feature得到检测区域patch的特征zf 
            %calculate response of the classifier at all shifts
			switch kernel.type
			case 'gaussian',
				kzf = gaussian_correlation(zf, model_xf, kernel.sigma);%由zf和model_xf计算高斯响应kzf 
			case 'polynomial',
				kzf = polynomial_correlation(zf, model_xf, kernel.poly_a, kernel.poly_b);
			case 'linear',
				kzf = linear_correlation(zf, model_xf);
			end
			response = real(ifft2(model_alphaf .* kzf));  %equation for fast detection model_alphaf与kzf点乘后进行傅里叶反变换，回到时域。保留实部，得到实数响应图response map，并且响应均为归一化值 

			%target location is at the maximum response. we must take into
			%account the fact that, if the target doesn't move, the peak
			%will appear at the top-left corner, not at the center (this is
			%discussed in the paper). the responses wrap around cyclically.
            %vert_delta, horiz_delta为response map上峰值最大处
			[vert_delta, horiz_delta] = find(response == max(response(:)), 1);
			if vert_delta > size(zf,1) / 2,  %wrap around to negative half-space of vertical axis
				vert_delta = vert_delta - size(zf,1);
			end
			if horiz_delta > size(zf,2) / 2,  %same for horizontal axis
				horiz_delta = horiz_delta - size(zf,2);
			end
			pos = pos + cell_size * [vert_delta - 1, horiz_delta - 1];
		end

		%obtain a subwindow for training at newly estimated target position
		patch = get_subwindow(im, pos, window_sz);
        %由benchamrk中的ground_truth或者自己框选出的第一帧目标位置
        %及之前计算出的检测范围window_sz，
        %利用get_subwindow获得图像中第一帧的检测的区域patch，
        %如果超过图像尺寸会加以修正。
        %作者的修正方法是认为超出部分的值都与边界的值相同。 
		xf = fft2(get_features(patch, features, cell_size, cos_window)); %利用get_feature获得第一帧patch的特征矩阵，再经过傅里叶变换到频率域得到xf 

		%Kernel Ridge Regression, calculate alphas (in Fourier domain)
		switch kernel.type
		case 'gaussian',
			kf = gaussian_correlation(xf, xf, kernel.sigma); %利用gaussian_correlation得到频率域上的高斯响应kf 
		case 'polynomial',
			kf = polynomial_correlation(xf, xf, kernel.poly_a, kernel.poly_b);
		case 'linear',
			kf = linear_correlation(xf, xf);
		end
		alphaf = yf ./ (kf + lambda);   %equation for fast training岭回归计算，得到分类器参数alphaf 
        
        %model_alphaf和model_xf随着时间更新，更新系数为主函数中设置的interp_factor
		if frame == 1,  %first frame, train with a single image
			model_alphaf = alphaf;
			model_xf = xf;
            %将以上得到的alphaf和xf作为第一帧时分类器训练的结果，初始化结束
		else
			%subsequent frames, interpolate model
			model_alphaf = (1 - interp_factor) * model_alphaf + interp_factor * alphaf;
			model_xf = (1 - interp_factor) * model_xf + interp_factor * xf;
		end

		%save position and timing   用position记录跟踪的目标中心位置，time累计时间 
		positions(frame,:) = pos;
		time = time + toc();

		%visualization跟踪结果可视化
		if show_visualization,
			box = [pos([2,1]) - target_sz([2,1])/2, target_sz([2,1])];
			stop = update_visualization(frame, box);
			if stop, break, end  %user pressed Esc, stop early
			
			drawnow
% 			pause(0.05)  %uncomment to run slower
		end
		
	end

	if resize_image,
		positions = positions * 2;
	end
end

